﻿using System;
using System.IO;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using VoxelBlock;using Vector3Int = VoxelBlock.Vector3Int;
using VoxelBlock.VoxelBlock3D;
using VoxelBlock.VoxelInput;

public class SaveReadWrite : MonoBehaviour
{
    [SerializeField]
    Camera mainCamera;

    [SerializeField]
    Camera readtCamera;

    [SerializeField]
    RenderTexture renderTexture;

    private Texture2D tempTexture2D;

    public Voxel3D[] ReadVox(string fileName)
    {
        string pathDirectory = Application.dataPath + "/" + VoxelCategories.USERDATA_PATH + "/" + VoxelCategories.SAVE_PATH
         + "/" + fileName;
        if (!File.Exists(pathDirectory + "/" + fileName + ".rvox"))
        {
            return new Voxel3D[0];
        }

        Voxel3D[] rvoxs = new Voxel3D[0];
        using (FileStream fs = new FileStream(pathDirectory + "/" + fileName + ".rvox", FileMode.Open))
        {
            using (System.IO.BinaryReader br = new BinaryReader(fs))
            {
                int length = br.ReadInt32();
                rvoxs = new Voxel3D[length];
                for (int i = 0; i < length; i++)
                {
                    int worldPositionX = br.ReadInt32();
                    int worldPositionY = br.ReadInt32();
                    int worldPositionZ = br.ReadInt32();
                    int uvKey = br.ReadInt32();
                    Voxel3D sVoxel = new Voxel3D(new Vector3Int(worldPositionX, worldPositionY, worldPositionZ), uvKey);
                    rvoxs[i] = sVoxel;
                }
            }
        }
        return rvoxs;
    }


    public RioVoxelData Read(string fileName, out ProxyOperation[] proxyOperations, Texture2D changeEditingTex)
    {
        proxyOperations = null;
        string pathDirectory = Application.dataPath + "/" + VoxelCategories.USERDATA_PATH + "/" + VoxelCategories.SAVE_PATH
         + "/" + fileName;
        if (!File.Exists(pathDirectory + "/" + fileName + ".riovox"))
        {
            return null;
        }

        RioVoxelData riovox = RioVoxelDataIO.Open(pathDirectory + "/" + fileName + ".riovox");
        Color32[] colors = new Color32[256];
        if (riovox.colors.Length <= 256)
        {
            riovox.colors.CopyTo(colors, 0);
        }
        tempTexture2D = new Texture2D(8, 32);
        tempTexture2D.filterMode = FilterMode.Point;
        tempTexture2D.SetPixels32(colors);
        UIComponentMastermind.instance.m_ColorPalatteComponent.showPalatte.mainTexture = VoxelEditorMastermind.instance.EditingTex = VoxelEditorMastermind.instance.userTexture = tempTexture2D;
        tempTexture2D.Apply();
        

        //Voxel3D[] rvoxs = new Voxel3D[0];
        //using (FileStream fs = new FileStream(pathDirectory + "/" + fileName + ".rvox", FileMode.Open))
        //{
        //    using (System.IO.BinaryReader br = new BinaryReader(fs))
        //    {
        //        int length = br.ReadInt32();
        //        rvoxs = new Voxel3D[length];
        //        for (int i = 0; i < length; i++)
        //        {
        //            int worldPositionX = br.ReadInt32();
        //            int worldPositionY = br.ReadInt32();
        //            int worldPositionZ = br.ReadInt32();
        //            int uvKey = br.ReadInt32();
        //            Voxel3D sVoxel = new Voxel3D(new Vector3Int(worldPositionX, worldPositionY, worldPositionZ), uvKey);
        //            rvoxs[i] = sVoxel;
        //        }

        //        int colorsLength = br.ReadInt32();
        //        Color32[] colors = new Color32[colorsLength];
        //        for (int i = 0; i < colorsLength; i++)
        //        {
        //            byte r = br.ReadByte();
        //            byte g = br.ReadByte();
        //            byte b = br.ReadByte();
        //            byte a = br.ReadByte();
        //            colors[i] = new Color32(r, g, b, a);
        //        }
        //        changeEditingTex.SetPixels32(colors);
        //        changeEditingTex.Apply();
        //    }
        //}

        if (!File.Exists(pathDirectory + "/" + fileName + ".voxHistoryRecord"))
        {
            return riovox;
        }
        using (FileStream fs = new FileStream(pathDirectory + "/" + fileName + ".voxHistoryRecord", FileMode.Open))
        {
            using (System.IO.BinaryReader br = new BinaryReader(fs))
            {
                int allProxyOperationLength = br.ReadInt32();
                proxyOperations = new ProxyOperation[allProxyOperationLength];
                for (int proxyIndex = 0; proxyIndex < allProxyOperationLength; proxyIndex++)
                {
                    int allHistoryRecordMaxPointer = br.ReadInt32();
                    ProxyOperation nowProxyOperation = new ProxyOperation(new HistoryRecordAPI<SerializeVoxelDatas, VoxelCategories.Operation>(allHistoryRecordMaxPointer));
                    proxyOperations[proxyIndex] = nowProxyOperation;

                    int allHistoryRecordLength = br.ReadInt32();
                    int pointer = br.ReadInt32();
                    for (int j = 0; j < allHistoryRecordLength; j++)
                    {
                        int breakDataLength = br.ReadInt32();
                        int frontDataLength = br.ReadInt32();
                        int m_Operation = br.ReadInt32();
                        VoxelCategories.Operation operation = (VoxelCategories.Operation)m_Operation;


                        if (operation == VoxelCategories.Operation.SelectAdd
                              ||
                              operation == VoxelCategories.Operation.SelectRemove
                              )
                        {
                            Vector3Int[] m_BreakData = new Vector3Int[breakDataLength];
                            Vector3Int[] m_FrontData = new Vector3Int[frontDataLength];
                            for (int i = 0; i < breakDataLength; i++)
                            {
                                int x = br.ReadInt32();
                                int y = br.ReadInt32();
                                int z = br.ReadInt32();
                                Vector3Int position = new Vector3Int(x, y, z);
                                m_BreakData[i] = position;
                            }
                            for (int i = 0; i < frontDataLength; i++)
                            {
                                int x = br.ReadInt32();
                                int y = br.ReadInt32();
                                int z = br.ReadInt32();
                                Vector3Int position = new Vector3Int(x, y, z);
                                m_BreakData[i] = position;
                            }
                            nowProxyOperation.Write((VoxelCategories.Operation)m_Operation, m_FrontData, m_BreakData);
                        }
                        else
                        {

                            SimpleVoxel[] m_BreakData = new SimpleVoxel[breakDataLength];
                            SimpleVoxel[] m_FrontData = new SimpleVoxel[frontDataLength];
                            for (int i = 0; i < breakDataLength; i++)
                            {
                                int uvKey = br.ReadInt32();
                                byte selectKey = br.ReadByte();
                                int x = br.ReadInt32();
                                int y = br.ReadInt32();
                                int z = br.ReadInt32();
                                Vector3Int position = new Vector3Int(x, y, z);
                                SimpleVoxel sVoxel = new SimpleVoxel(position, uvKey, selectKey);
                                m_BreakData[i] = sVoxel;
                            }
                            for (int i = 0; i < frontDataLength; i++)
                            {
                                int uvKey = br.ReadInt32();
                                byte selectKey = br.ReadByte();
                                int x = br.ReadInt32();
                                int y = br.ReadInt32();
                                int z = br.ReadInt32();
                                Vector3Int position = new Vector3Int(x, y, z);
                                SimpleVoxel sVoxel = new SimpleVoxel(position, uvKey, selectKey);
                                m_FrontData[i] = sVoxel;
                            }
                            nowProxyOperation.Write((VoxelCategories.Operation)m_Operation, m_FrontData, m_BreakData);
                        }


                    }

                    nowProxyOperation.SetPointer(pointer);
                }
               
            }
        }


        return riovox;
    }
    public static bool IsFileExists(string fileName)
    {
        
        string pathDirectory = Application.dataPath + "/" + VoxelCategories.USERDATA_PATH + "/" + VoxelCategories.SAVE_PATH
         + "/" + fileName + "/" + fileName + ".riovox";
        return File.Exists(pathDirectory);
    }

    public void Write(string fileName, ProxyOperation[] proxyOperations, RioVoxelData riovox, Texture2D uvTexture2D)
    {
        readtCamera.orthographic = mainCamera.orthographic;
        if (readtCamera.orthographic)
        {
            readtCamera.orthographicSize = mainCamera.orthographicSize;
        }
        else
        {
            readtCamera.fieldOfView = mainCamera.fieldOfView;
        }
         
        string pathDirectory = Application.dataPath + "/" + VoxelCategories.USERDATA_PATH + "/" + VoxelCategories.SAVE_PATH
            + "/" + fileName;
        if (!Directory.Exists(pathDirectory))
        {
            Directory.CreateDirectory(pathDirectory);
        }

        //保存数据
        RioVoxelDataIO.Save(pathDirectory + "/" + fileName + ".riovox", riovox);
#if UNITY_EDITOR
        using (FileStream fs = new FileStream(pathDirectory + "/" + fileName + ".voxHistoryRecord", FileMode.Create))
        {
            using (BinaryWriter br = new BinaryWriter(fs))
            {
                br.Write(proxyOperations.Length);
                foreach (var nowProxyOperation in proxyOperations)
                {
                    br.Write(nowProxyOperation.GetHistoryRecord().MaxStep);
                    br.Write(nowProxyOperation.GetHistoryRecord().HistoryRecord.Count);
                    br.Write(nowProxyOperation.GetPointer());
                    foreach (var itemRecordData in nowProxyOperation.GetHistoryRecord().HistoryRecord)//.m_FrontData
                    {
                        if (itemRecordData.m_Operation == VoxelCategories.Operation.SelectAdd
                            ||
                            itemRecordData.m_Operation == VoxelCategories.Operation.SelectRemove
                            )
                        {
                            br.Write(itemRecordData.m_BreakData.positions.Count());
                            br.Write(itemRecordData.m_FrontData.positions.Count());
                            br.Write((int)itemRecordData.m_Operation);
                            foreach (var position in itemRecordData.m_BreakData.positions)
                            {
                                br.Write(position.x);
                                br.Write(position.y);
                                br.Write(position.z);
                            }
                            foreach (var position in itemRecordData.m_FrontData.positions)
                            {
                                br.Write(position.x);
                                br.Write(position.y);
                                br.Write(position.z);
                            }
                        }
                        else
                        {
                            br.Write(itemRecordData.m_BreakData.voxels.Count());
                            br.Write(itemRecordData.m_FrontData.voxels.Count());
                            br.Write((int)itemRecordData.m_Operation);
                            foreach (var voxel in itemRecordData.m_BreakData.voxels)
                            {
                                br.Write(voxel.uvKey);
                                br.Write(voxel.selectKey);
                                br.Write(voxel.position.x);
                                br.Write(voxel.position.y);
                                br.Write(voxel.position.z);
                            }
                            foreach (var voxel in itemRecordData.m_FrontData.voxels)
                            {
                                br.Write(voxel.uvKey);
                                br.Write(voxel.selectKey);
                                br.Write(voxel.position.x);
                                br.Write(voxel.position.y);
                                br.Write(voxel.position.z);
                            }
                        }
                    }
                }
            }
        }
#endif
        //保存图片
        //StartCoroutine(RenderTextureToTexture2D(renderTexture, fileName, pathDirectory));
        RenderTextureToTexture2D2(renderTexture, fileName, pathDirectory);

        
    }

    public void Delete(string fileName)
    {
        string pathDirectory = Application.dataPath + "/" + VoxelCategories.USERDATA_PATH + "/" + VoxelCategories.SAVE_PATH
            + "/" + fileName;
        if (Directory.Exists(pathDirectory))
        {
            //DelectDir(pathDirectory);
            DirectoryInfo dir = new DirectoryInfo(pathDirectory);
            dir.Delete(true);
        }
    }
    public static void DelectDir(string srcPath)
    {
        try
        {
            DirectoryInfo dir = new DirectoryInfo(srcPath);
            FileSystemInfo[] fileinfo = dir.GetFileSystemInfos();  //返回目录中所有文件和子目录
            foreach (FileSystemInfo i in fileinfo)
            {
                if (i is DirectoryInfo)            //判断是否文件夹
                {
                    DirectoryInfo subdir = new DirectoryInfo(i.FullName);
                    subdir.Delete(true);          //删除子目录和文件
                }
                else
                {
                    File.Delete(i.FullName);      //删除指定文件
                }
            }
            dir.Delete(true);
        }
        catch (Exception e)
        {
            throw;
        }
    }
    private void RenderTextureToTexture2D2(RenderTexture renderT, string fileName, string pathDirectory)
    {
        if (renderT == null)
        {
            return ;
        }

        int width = renderT.width;
        int height = renderT.height;
        tempTexture2D = new Texture2D(width, height);
        RenderTexture.active = renderT;
        tempTexture2D.ReadPixels(new Rect(0, 0, width, height), 0, 0);
        tempTexture2D.Apply();

        pathDirectory += "/" + fileName + ".png";
        if (tempTexture2D != null)
        {
            File.WriteAllBytes(pathDirectory, tempTexture2D.EncodeToPNG());
        }
    }


    private IEnumerator RenderTextureToTexture2D(RenderTexture renderT, string fileName,string pathDirectory)
    {
        yield return new WaitForEndOfFrame();
        if (renderT == null)
        {
            goto OVER;
        }

        int width = renderT.width;
        int height = renderT.height;
        tempTexture2D = new Texture2D(width, height);
        RenderTexture.active = renderT;
        tempTexture2D.ReadPixels(new Rect(0, 0, width, height), 0, 0);
        tempTexture2D.Apply();

       
        pathDirectory += "/" + fileName + ".png";
        if (tempTexture2D != null)
        {
            File.WriteAllBytes(pathDirectory, tempTexture2D.EncodeToPNG());
        }

        OVER:
        yield return new WaitForEndOfFrame();

    }

}
